/*
 * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

const char *
_umem_debug_init(void)
{
	return ("default,verbose");
}

const char *
_umem_logging_init(void)
{
	return ("fail,contents");
}

int
simpletest(void)
{
	FILE	*s1, *s2;
	char	 string[] = "fmemopen test string!";
	char	 buffer[1024], *buf = NULL;
	size_t	 len;
	int	 c, failures = 0;

	s1 = fmemopen(string, strlen(string) + 1, "r");
	if (s1 == NULL) {
		warn("unable to open a stream s1");
		return (1);
	}

	s2 = fmemopen(buf, 22, "w+");
	if (s2 == NULL) {
		warn("unable to create a stream s2");
		(void) fclose(s1);
		return (1);
	}

	while ((c = fgetc(s1)) != EOF)
		(void) fputc(c, s2);

	if (ftell(s2) != strlen(string) + 1) {
		warnx("failed copy test (1)");
		failures++;
	}
	(void) fclose(s1);

	(void) fseek(s2, 0, SEEK_SET);
	if (ftell(s2) != 0) {
		warnx("failed seek test (2)");
		failures++;
	}

	len = fread(buffer, 1, sizeof(buffer) - 1, s2);
	if (len != strlen(string) + 1) {
		warnx("failed read test (3) %zu != %zu",
		    len, strlen(string) + 1);
		failures++;
	}

	return (failures);
}

int
updatetest(void)
{
	FILE	*s1;
	char	 string[] = "hello\0 test number 2";
	char	 buffer[256];
	size_t	 len;
	int	 failures = 0;

	s1 = fmemopen(string, 19, "a+");
	if (s1 == NULL)
		return (1);

	len = fwrite(" world", 1, 6, s1);
	if (len != 6) {
		warnx("failed write test (4)");
		failures++;
	}

	(void) fseek(s1, 0, SEEK_SET);
	if (ftell(s1) != 0) {
		warnx("failed seek test (5)");
		failures++;
	}

	len = fread(buffer, 1, sizeof(buffer) - 1, s1);
	if (strncmp(string, buffer, len)) {
		warnx("failed compare test (6)");
		failures++;
	}

	if (strcmp(string, "hello world")) {
		warnx("failed compare test (7)");
		failures++;
	}

	if (strcmp(string + strlen(string) + 1, "number 2")) {
		warnx("failed compare test (8)");
		failures++;
	}

	return (failures);
}

int
writetest(void)
{
	FILE	*s1;
	char	 string[] = "super test number 3";
	char	 buffer[256];
	size_t	 len, slen;
	int	 failures = 0;

	slen = strlen(string) + 1;

	s1 = fmemopen(string, slen, "w");
	if (s1 == NULL)
		return (1);

	len = fwrite("short", 1, 5, s1);
	if (len != strlen("short")) {
		warnx("failed write test (9)");
		failures++;
	}
	(void) fclose(s1);

	s1 = fmemopen(string, slen, "r");
	if (s1 == NULL) {
		warnx("failed open test (10)");
		failures++;
	}

	len = fread(buffer, 1, sizeof(buffer) - 1, s1);
	if (strncmp(string, buffer, len)) {
		warnx("failed compare test (11)");
		failures++;
	}

	if (strcmp(string, "short")) {
		warnx("failed compare test (12)");
		failures++;
	}

	if (strcmp(string + strlen(string) + 1, "test number 3")) {
		warnx("failed compare test (13)");
		failures++;
	}

	return (failures);
}

int
seektest(void)
{
	FILE	*s1;
	char	 string[] = "long string for testing seek";
	size_t	 slen;
	int	 failures = 0;

	slen = strlen(string) + 1;

	s1 = fmemopen(string, slen, "r");
	if (s1 == NULL)
		return (1);

	if (fseek(s1, 8, SEEK_SET) != 0) {
		warnx("failed to fseek. (14)");
		failures++;
	}

	if (ftell(s1) != 8) {
		warnx("failed seek test. (15)");
		failures++;
	}

	/* Try to seek backward */
	if (fseek(s1, -1, SEEK_CUR) != 0) {
		warnx("failed to fseek. (16)");
		failures++;
	}

	if (ftell(s1) != 7) {
		warnx("failed seeking backward. (17)");
		failures++;
	}

	return (failures);
}

int
main(void)
{
	int	 failures = 0;

	failures += simpletest();
	failures += updatetest();
	failures += writetest();
	failures += seektest();

	return (failures);
}
